package com.yunxi.poc.starbucks.service.impl;

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.yunxi.poc.starbucks.common.BizConstant;
import com.yunxi.poc.starbucks.entity.CoordinateDistance;
import com.yunxi.poc.starbucks.entity.Tb1Store;
import com.yunxi.poc.starbucks.service.ICoordinateDistanceService;
import com.yunxi.poc.starbucks.service.ISatisfiedService;
import com.yunxi.poc.starbucks.util.CacheUtil;
import com.yunxi.poc.starbucks.util.DistanceUtil;
import com.yunxi.poc.starbucks.vo.StoreRateVO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;

@Service
public class SatisfiedServiceImpl implements ISatisfiedService {

    @Resource
    ICoordinateDistanceService coordinateDistanceService;

    @Value("${biz.satisfied.direction-service-key}")
    private String DIRECTION_SERVICE_KEY;

    @Override
    public double scoreSatisfied(double longitude, double latitude, Tb1Store store, StoreRateVO calRes) {
        return "simple".equals(BizConstant.SATISFIED_DISTANCE_TYPE) ?
                this.scoreSatisfiedSimple(longitude, latitude, store, calRes) :
                this.scoreSatisfiedDirection(longitude, latitude, store, calRes);
    }

    @Override
    public double scoreSatisfiedSimple(double longitude, double latitude, Tb1Store store, StoreRateVO calRes) {
        double longitudeStore = Double.parseDouble(store.getLongitude());
        double latitudeStore = Double.parseDouble(store.getLatitude());
        double distanceX = DistanceUtil.getDistance(longitude, latitude, longitudeStore, latitude);
        double distanceY = DistanceUtil.getDistance(longitudeStore, latitude, longitudeStore, latitudeStore);
        double score = Math.max(distanceX + distanceY - BizConstant.SATISFIED_DEFAULT_DISTANCE, 0);

        calRes.setSatisfiedDistanceX(String.valueOf(distanceX));
        calRes.setSatisfiedDistanceY(String.valueOf(distanceY));
        calRes.setSatisfiedLon(String.valueOf(longitudeStore));
        calRes.setSatisfiedLat(String.valueOf(latitudeStore));

        return new BigDecimal(score).setScale(2, RoundingMode.DOWN).doubleValue();
    }

    @Override
    public double scoreSatisfiedDirection(double longitude, double latitude, Tb1Store store, StoreRateVO calRes) {
        calRes.setSatisfiedLon(store.getLongitude());
        calRes.setSatisfiedLat(store.getLatitude());

        // 额度有限，从缓存中获取
        String key = store.getLongitude() + "," + store.getLatitude() + "-" + longitude + "," + latitude;
        if (CacheUtil.coordinateDistances.containsKey(key)) {
            calRes.setSatisfiedDistanceDirection(CacheUtil.coordinateDistances.get(key));
            return Math.max(Double.parseDouble(CacheUtil.coordinateDistances.get(key)) - BizConstant.SATISFIED_DEFAULT_DISTANCE, 0);
        }

        String result1 = HttpUtil.get("https://restapi.amap.com/v4/direction/bicycling?" + "key=" + DIRECTION_SERVICE_KEY +
                "&" + "origin=" + store.getLongitude() + "," + store.getLatitude() +
                "&" + "destination=" + longitude + "," + latitude);

        JSONObject res = JSONUtil.parseObj(result1);
        Integer errcode = res.get("errcode", Integer.class);
        if (errcode != 0) {
            calRes.setTag("WARN");
            calRes.getMsg().add("get distance by direction error: " + res.get("errmsg", String.class) + " detail: " + res.get("errdetail", String.class));
            return 99999;
        }
        Double distance = res.getByPath("data.paths[0].distance", Double.class) / 1000;

        // insert db
        CoordinateDistance cd = new CoordinateDistance();
        cd.setCoordinate(key);
        cd.setDistance(distance.toString());
        this.coordinateDistanceService.save(cd);
        // update cache
        CacheUtil.coordinateDistances.put(key, distance.toString());

        calRes.setSatisfiedDistanceDirection(String.valueOf(distance));

        this.scoreSatisfiedSimple(longitude, latitude, store, calRes);

        distance = Math.max(distance - BizConstant.SATISFIED_DEFAULT_DISTANCE, 0);
        return new BigDecimal(distance).setScale(2, RoundingMode.DOWN).doubleValue();
    }

}
